package top.happylaishop.shop.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.happylaishop.shop.common.Const;
import top.happylaishop.shop.dao.*;
import top.happylaishop.shop.dto.OrderDto;
import top.happylaishop.shop.dto.OrderItemDto;
import top.happylaishop.shop.dto.ShippingDto;
import top.happylaishop.shop.dto.UserDto;
import top.happylaishop.shop.exception.BaseRuntimeException;
import top.happylaishop.shop.pojo.*;
import top.happylaishop.shop.service.CartService;
import top.happylaishop.shop.service.OrderService;
import top.happylaishop.shop.utils.CommonUtils;
import top.happylaishop.shop.utils.PageDto;
import top.happylaishop.shop.utils.SnowFlake;
import top.happylaishop.shop.utils.resp.BaseResponse;
import top.happylaishop.shop.utils.resp.RestResponse;
import top.happylaishop.shop.vo.CreateOrderVo;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderDao orderDao;
    @Autowired
    private OrderItemDao orderItemDao;
    @Autowired
    private ShippingDao shippingDao;
    @Autowired
    private ProductDao productDao;
    @Autowired
    private PayInfoDao payInfoDao;
    @Autowired
    private CartService cartService;
    @Autowired
    private SnowFlake snowFlake;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResponse<OrderDto> create(UserDto currentUserInfo, CreateOrderVo createOrderVo) {
        List<Cart> cartList = cartService.listSelected(currentUserInfo.getId());
        RestResponse<List<OrderItem>> restResponse = this.getCartOrderItem(currentUserInfo, cartList);
        if(!restResponse.isSuccess()) {
            return new RestResponse<>(restResponse.getStatus(), restResponse.getMessage());
        }
        List<OrderItem> orderItemList = restResponse.getData();
        BigDecimal totalPrice = this.getOrderTotalPrice(orderItemList);
        // 生成订单
        Order order = this.assembleOrder(currentUserInfo, createOrderVo, totalPrice);
        if(order == null){
            return RestResponse.failed("生成订单失败");
        }
        for (OrderItem orderItem : orderItemList) {
            orderItem.setOrderNo(order.getOrderNo());
        }
        orderItemDao.batchInsert(orderItemList);
        // 扣减库存
        this.reduceProductStock(orderItemList);
        // 清空购物车
        this.cleanCart(cartList);
        // 返回数据返回前端
        OrderDto orderDto = assembleOrderDto(order, orderItemList);
        return RestResponse.defaultSucessData(orderDto);
    }

    @Override
    public BaseResponse cancel(UserDto currentUserInfo, String orderNo) {
        Order order = this.getOrderByUserIdOrderNo(currentUserInfo.getId(), orderNo);
        if(order == null){
            return BaseResponse.failed("订单不存在");
        }
        if(order.getStatus() == Const.OrderStatusEnum.CANCELED.getCode()){
            return new BaseResponse(HttpStatus.OK.value(), "订单已取消");
        }
        if(order.getStatus() != Const.OrderStatusEnum.NO_PAY.getCode()){
            return BaseResponse.failed("订单已付款，不能取消");
        }
        Order orderUpdate = new Order();
        orderUpdate.setId(order.getId());
        orderUpdate.setStatus(Const.OrderStatusEnum.CANCELED.getCode());
        int count = orderDao.updateById(orderUpdate);
        if(count < 1){
            return BaseResponse.failed();
        }
        return BaseResponse.success();
    }

    @Override
    public RestResponse<OrderDto> getDetailByOrderNo(UserDto currentUserInfo, String orderNo) {
        Order order = getOrderByUserIdOrderNo(currentUserInfo.getId(), orderNo);
        if(order == null){
            return RestResponse.failed("未找到订单");
        }
        List<OrderItem> orderItemList = getOrderItemListByOrderNo(currentUserInfo.getId(), orderNo);
        return RestResponse.defaultSucessData(assembleOrderDto(order, orderItemList));
    }

    @Override
    public void list(UserDto currentUserInfo, PageDto<OrderDto> orderPageDto) {
        Page<Order> orderPage = new Page<>(orderPageDto.getPage(), orderPageDto.getSize());
        orderDao.selectPage(orderPage, null);
        orderPageDto.setTotal(orderPage.getTotal());
        orderPageDto.setList(BeanUtil.copyToList(orderPage.getRecords(), OrderDto.class));
    }

    @Override
    public RestResponse<OrderDto> getCurrentOrder(UserDto currentUserInfo) {
        OrderDto orderDto = new OrderDto();
        List<Cart> cartList = cartService.listSelected(currentUserInfo.getId());
        //计算这个订单的总价
        RestResponse<List<OrderItem>> restResponse = this.getCartOrderItem(currentUserInfo, cartList);
        if(!restResponse.isSuccess()) {
            return new RestResponse<>(restResponse.getStatus(), restResponse.getMessage());
        }
        List<OrderItem> orderItemList = restResponse.getData();
        orderDto.setPayment(this.getOrderTotalPrice(orderItemList));
        orderDto.setOrderItemDtoList(BeanUtil.copyToList(orderItemList, OrderItemDto.class));
        return RestResponse.defaultSucessData(orderDto);
    }

    private List<OrderItem> getOrderItemListByOrderNo(Integer userId, String orderNo) {
        LambdaQueryWrapper<OrderItem> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(OrderItem :: getUserId, userId).in(OrderItem::getOrderNo, orderNo);
        return orderItemDao.selectList(lambdaQueryWrapper);
    }

    private Order getOrderByUserIdOrderNo(Integer userId, String orderNo) {
        LambdaQueryWrapper<Order> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Order :: getUserId, userId).in(Order::getOrderNo, orderNo);
        return orderDao.selectOne(lambdaQueryWrapper);
    }

    private OrderDto assembleOrderDto(Order order, List<OrderItem> orderItemList) {
        OrderDto orderDto = new OrderDto();
        orderDto.setOrderNo(order.getOrderNo());
        orderDto.setPayment(order.getPayment());
        orderDto.setPaymentType(order.getPaymentType());
        orderDto.setPaymentTypeDesc(Const.PaymentTypeEnum.codeOf(order.getPaymentType()).getValue());

        orderDto.setPostage(order.getPostage());
        orderDto.setStatus(order.getStatus());
        orderDto.setStatusDesc(Const.OrderStatusEnum.codeOf(order.getStatus()).getValue());

        orderDto.setShippingId(order.getShippingId());
        Shipping shipping = shippingDao.selectById(order.getShippingId());
        if(shipping != null){
            orderDto.setReceiverName(shipping.getReceiverName());
            orderDto.setShippingDto(BeanUtil.copyProperties(shipping, ShippingDto.class));
        }
        orderDto.setPaymentTime(DateUtil.formatDateTime(order.getPaymentTime()));
        orderDto.setSendTime(DateUtil.formatDateTime(order.getSendTime()));
        orderDto.setEndTime(DateUtil.formatDateTime(order.getEndTime()));
        orderDto.setCreateTime(DateUtil.formatDateTime(order.getCreateTime()));
        orderDto.setCloseTime(DateUtil.formatDateTime(order.getCreateTime()));

        List<OrderItemDto> orderItemDtoList = BeanUtil.copyToList(orderItemList, OrderItemDto.class);
        orderDto.setOrderItemDtoList(orderItemDtoList);
        return orderDto;
    }

    private void reduceProductStock(List<OrderItem> orderItemList) {
        for (OrderItem orderItem : orderItemList) {
            int count = productDao.updateSubStockById(orderItem.getId(), orderItem.getQuantity());
            if(count < 1){
                throw new BaseRuntimeException("库存不足");
            }
        }
    }

    private void cleanCart(List<Cart> cartList) {
        List<Integer> idList = cartList.stream().map(Cart::getId).collect(Collectors.toList());
        cartService.deleteByIds(idList);
    }

    private Order assembleOrder(UserDto currentUserInfo, CreateOrderVo createOrderVo, BigDecimal totalPrice) {
        Order order = new Order();
        order.setOrderNo(snowFlake.nextId());
        order.setStatus(Const.OrderStatusEnum.NO_PAY.getCode());
        order.setPostage(0);
        order.setPaymentType(Const.PaymentTypeEnum.ONLINE_PAY.getCode());
        order.setPayment(totalPrice);
        order.setUserId(currentUserInfo.getId());
        order.setShippingId(createOrderVo.getShippingId());
        order.setCreateTime(new Date());
        order.setUpdateTime(order.getCreateTime());
        int count = orderDao.insert(order);
        if(count > 0){
            return order;
        }
        return null;
    }

    private BigDecimal getOrderTotalPrice(List<OrderItem> orderItemList) {
        BigDecimal totalPrice = new BigDecimal("0");
        for (OrderItem orderItem : orderItemList) {
            totalPrice = totalPrice.add(orderItem.getTotalPrice());
        }
        return totalPrice;
    }

    private RestResponse<List<OrderItem>> getCartOrderItem(UserDto currentUserInfo, List<Cart> cartList) {
        if(CollectionUtil.isEmpty(cartList)) {
            return RestResponse.failed("购物车为空");
        }
        List<OrderItem> orderItemDtos = new ArrayList<>();
        for (Cart cartItem : cartList) {
            OrderItem orderItem = new OrderItem();
            Product product = productDao.selectById(cartItem.getProductId());
            if(Const.ProductStatusEnum.ON_SALE.getCode() != product.getStatus()){
                return RestResponse.failed("产品【" +  product.getName() + "】不是在线售卖状态");
            }
            if(product.getStock() < cartItem.getQuantity()){
                return RestResponse.failed("产品【" + product.getName() + "】库存不足");
            }
            orderItemDtos.add(orderItem);
            orderItem.setUserId(currentUserInfo.getId());
            orderItem.setProductId(product.getId());
            orderItem.setProductName(product.getName());
            orderItem.setProductImage(product.getMainImage());
            orderItem.setCurrentUnitPrice(product.getPrice());
            orderItem.setQuantity(cartItem.getQuantity());
            orderItem.setTotalPrice(CommonUtils.mul(product.getPrice().doubleValue(),cartItem.getQuantity()));
        }
        return RestResponse.defaultSucessData(orderItemDtos);
    }
}
